#include "mem_leak_chk.h"
#include "mem_chk_db.h"

#include <stdlib.h>
#include <string.h>
#include <execinfo.h>

extern "C" {
    void get_trace (char** bt) {
        void *array[10];
        size_t size;
        char **strings;
		size_t i;
		
        size = backtrace (array, 10);
        strings = backtrace_symbols (array, size);
        if (NULL == strings) {
			perror("backtrace_synbols");
			return;
        }

		int alloc_len = 0;
        for (i = 1; i < size; i++) {
        	alloc_len += (strlen(strings[i]) + ENTER_LEN);
        }
        alloc_len += 1;
        char* _bt = (char*)__real_malloc(alloc_len);
        memset(_bt, 0, alloc_len);

        for (i = 1; i < size; i++) {
        	strcat(_bt, strings[i]);
        	strcat(_bt, ENTER_STR);
        }

        __real_free(strings);
        strings = NULL;
        *bt = _bt;
    }
    
    void* __wrap_malloc (size_t c) {
        void* ptr = (void*)__real_malloc(c);
        //printf ("malloc called. size=%zu, ptr=%p\n", c, ptr);
        if(NULL != ptr) {
			MemChkInfo inf;
			inf.ptr = ptr;
			inf.alloc_len = c;
			get_trace(&inf.backtrace);
			add_mem_chk_node(&inf);
        }
        return ptr;
    }
    
    void *__wrap_calloc(size_t nmemb, size_t size) {
        void* ptr = (void*)__real_calloc(nmemb, size);
        if(NULL != ptr) {
			MemChkInfo inf;
			inf.ptr = ptr;
			inf.alloc_len = nmemb * size;
			get_trace(&inf.backtrace);
			add_mem_chk_node(&inf);
        }
        return ptr;
    }
    
	void *__wrap_realloc(void *ptr, size_t size) {
        rm_mem_chk_node(ptr);
        ptr = (void*)__real_realloc(ptr, size);
        if(NULL != ptr) {
			MemChkInfo inf;
			inf.ptr = ptr;
			inf.alloc_len = size;
			get_trace(&inf.backtrace);
			add_mem_chk_node(&inf);
        }
        return ptr;
    }
    
    void __wrap_free(void* ptr) {
        //printf("free ptr=%p\n", ptr);
        rm_mem_chk_node(ptr);
        __real_free(ptr);
    }
    //void* __wrap__Znaj(unsigned int c) {//operator new[](unsigned int)
    void* __wrap__Znam(unsigned int c) {//operator new[](unsigned int)
        //void* ptr = (void*)__real__Znaj(c);
        void* ptr = (void*)__real__Znam(c);
        //printf ("new called. size=%zu, ptr=%p\n", c, ptr);
        if(NULL != ptr) {
		    MemChkInfo inf;
		    inf.ptr = ptr;
		    inf.alloc_len = c;
		    get_trace(&inf.backtrace);
		    add_mem_chk_node(&inf);
		}
        return ptr;
    }
    
    void __wrap__ZdaPv(void* ptr) {//operator delete[](void*)
        //printf("delete[] ptr=%p\n", ptr);
        rm_mem_chk_node(ptr);
        __real__ZdaPv(ptr);
    }
    
    //void* __wrap__Znwj(unsigned int c) {//operator new(unsigned int)
    void* __wrap__Znwm(unsigned int c) {//operator new(unsigned int)
        //void* ptr = (void*)__real__Znwj(c);
        void* ptr = (void*)__real__Znwm(c);

        //printf ("class new called. size=%zu, ptr=%p\n", c, ptr);
        if(NULL != ptr) {
		    MemChkInfo inf;
		    inf.ptr = ptr;
		    inf.alloc_len = c;
		    get_trace(&inf.backtrace);
		    add_mem_chk_node(&inf);
		}
        return ptr;
    }
    
    void __wrap__ZdlPv(void* ptr) {//operator delete(void*)
        //printf("delete ptr=%p\n", ptr);
        rm_mem_chk_node(ptr);
        __real__ZdlPv(ptr);
    }
    
}